﻿// 版权所有 (C) Microsoft Corporation。保留所有权利。

// SuppressSecurity.cs
using System;
using System.Security;
using System.Security.Permissions;
using System.Runtime.InteropServices;

class NativeMethods
{
    // 这是对非托管代码的调用。执行此方法需要
    // UnmanagedCode 安全权限。如果没有此权限，
    // 则调用此方法的尝试将引发 SecurityException：
    /* 注意：SuppressUnmanagedCodeSecurityAttribute 禁止
       在运行时检查 UnmanagedCode 权限。一定要小心！*/
    [SuppressUnmanagedCodeSecurityAttribute()]
    [DllImport("msvcrt.dll")]
    internal static extern int puts(string str);
    [SuppressUnmanagedCodeSecurityAttribute()]
    [DllImport("msvcrt.dll")]
    internal static extern int _flushall();
}

class MainClass
{
    // 附加到此方法的安全权限在
    // 调用此方法期间将从当前权限集中移除
    // UnmanagedCode 权限。
    // 即使 CallUnmanagedCodeWithoutPermission 方法是
    // 在已经为非托管代码调用了
    // Assert 的堆栈帧中调用的，也无法调用本机代码。
    // 由于此方法附加了非托管代码的 Deny 权限，
    // 因此相应的安全权限被覆盖。但是，由于
    // 此处使用的是 SuppressUnmanagedCodeSecurityAttribute，因此
    // 仍可以成功调用非托管方法。
    // 该代码应使用其他安全检查方法，以确保不会
    // 出现安全漏洞。
    [SecurityPermission(SecurityAction.Deny, Flags = 
       SecurityPermissionFlag.UnmanagedCode)]
    private static void CallUnmanagedCodeWithoutPermission()
    {
        try
        {
            // UnmanagedCode 安全检查在下面的调用中
            // 被禁用。但非托管调用仅显示用户界面。
            // 如果存在用户界面权限，则通过只允许非托管 
            // 调用可以确保安全。
            UIPermission uiPermission = 
               new UIPermission(PermissionState.Unrestricted);
            uiPermission.Demand();

            Console.WriteLine("Attempting to call unmanaged code without UnmanagedCode permission.");
            NativeMethods.puts("Hello World!");
            NativeMethods._flushall();
            Console.WriteLine("Called unmanaged code without UnmanagedCode permission.");
        }
        catch (SecurityException)
        {
            Console.WriteLine("Caught Security Exception attempting to call unmanaged code.");
        }
    }

    // 附加到此方法的安全权限在调用此方法
    // 期间将 UnmanagedCode
    // 权限添加到当前权限集中。
    // 即使 CallUnmanagedCodeWithPermission 方法是
    // 在已经为非托管代码调用了
    // Deny 的堆栈帧中调用的，也不会妨碍您调用
    // 本机代码。由于此方法附加了非托管代码的 Assert 权限，
    // 因此相应的安全权限被覆盖。
    // 由于此处使用的是 SuppressUnmanagedCodeSecurityAttribute，因此
    // 可以成功调用非托管方法。
    // 即使您没有权限，
    // SuppressUnmanagedCodeSecurityAttribute 也会使操作成功。
    [SecurityPermission(SecurityAction.Assert, Flags = 
       SecurityPermissionFlag.UnmanagedCode)]
    private static void CallUnmanagedCodeWithPermission()
    {
        try
        {
            Console.WriteLine("Attempting to call unmanaged code with permission.");
            NativeMethods.puts("Hello World!");
            NativeMethods._flushall();
            Console.WriteLine("Called unmanaged code with permission.");
        }
        catch (SecurityException)
        {
            Console.WriteLine("Caught Security Exception attempting to call unmanaged code. Whoops!");
        }
    }

    public static void Main() 
    {
        SecurityPermission perm = new
            SecurityPermission(SecurityPermissionFlag.UnmanagedCode);

       // 该方法本身附加了非托管代码
       // 的安全权限 Deny，这会重写
       // 此堆栈帧中的 Assert 权限。但是，由于使用的是
       // SuppressUnmanagedCodeSecurityAttribute，因此仍可以成功调用
       // 非托管方法。
       // 该代码应使用其他安全检查方法，以确保
       // 不会出现安全漏洞。
       perm.Assert();
       CallUnmanagedCodeWithoutPermission();

       // 该方法本身附加了非托管代码
       // 的安全权限 Assert，这会重写
       // 此堆栈帧中的 Deny 权限。由于此处使用的是
       // SuppressUnmanagedCodeSecurityAttribute，因此可以成功调用
       // 非托管方法。
       // 即使您没有权限，
       // SuppressUnmanagedCodeSecurityAttribute 也会使操作成功。
       perm.Deny();
       CallUnmanagedCodeWithPermission();
    }
}

